﻿using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
using EnvDTE;
using Microsoft.VisualStudio.Shell;

namespace HQLAddin.ConfigurationInspector
{
	public interface IPathProvider
	{
		IEnumerable<string> FindPaths();
	}

	[Export(typeof(IPathProvider))]
	internal class PathProvider : IPathProvider
	{
		private readonly DTE dte;

		public PathProvider() : this((DTE)Package.GetGlobalService(typeof(DTE))) {}

		public PathProvider(DTE dte)
		{
			this.dte = dte;
		}

		public virtual IEnumerable<string> FindPaths()
		{
			var projects = dte.Solution.Projects.OfType<Project>().ToArray();
			foreach (var candidate in projects
											.Where(project => project.ConfigurationManager != null)
											.Select(GetAssemblyPath)
											.Where(candidate => !string.IsNullOrEmpty(candidate)))
			{
				yield return candidate;
			}

			var pathsOfProjectsOnSolutionFolders = from project in projects
													where project.ConfigurationManager == null && project.ProjectItems != null
													from projectItem in project.ProjectItems.OfType<ProjectItem>()
			                 						from innerProject in NavigateProjectItems(projectItem)
													let candidate = GetAssemblyPath(innerProject)
													where !string.IsNullOrEmpty(candidate)
													select candidate;

			foreach (var candidate in pathsOfProjectsOnSolutionFolders)
			{
				yield return candidate;
			}
		}

		private static IEnumerable<Project> NavigateProjectItems(ProjectItem projectItem)
		{
			if (projectItem.SubProject == null) yield break;
			if (projectItem.SubProject.ConfigurationManager != null)
			{
				yield return projectItem.SubProject;
			}
			else
			{
				if (projectItem.SubProject.ProjectItems != null)
				{
					foreach (var navigateProjectItem in 
						projectItem.SubProject.ProjectItems.OfType<ProjectItem>().SelectMany(NavigateProjectItems))
					{
						yield return navigateProjectItem;
					}
				}
			}
		}

		static string GetAssemblyPath(Project project)
		{
			if (!project.Properties.OfType<Property>().Any(p => p.Name == "FullPath")) return string.Empty;
			var fullPath = project.Properties.Item("FullPath").Value.ToString();
			var outputPath = project.ConfigurationManager.ActiveConfiguration.Properties.Item("OutputPath").Value.ToString();
			return Path.GetDirectoryName(Path.Combine(fullPath, outputPath));
		}
	}
}